﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Athena.Tools
{
    public partial class ModuleViewer : Athena.Tools.IGUITool
    {
        public override void SetupToolStrip(ToolStrip oStrip)
        {
            /*
            ToolStripButton oButton = new ToolStripButton();
            oButton.Text = Text;
            oButton.ToolTipText = "Module overview";
            oButton.Click += new EventHandler(ShowHide_Click);
            oStrip.Items.Add(oButton);
             */
        }

        public override void SetupDockPanel(WeifenLuo.WinFormsUI.Docking.DockPanel oPanel)
        {
            this.DockPanel = oPanel;
            //if (IsHidden) Show();
            DockState = WeifenLuo.WinFormsUI.Docking.DockState.DockRight;
            this.DockPanel.DockRightPortion = 300;
        }

        public override void ShowHide_Click(object sender, EventArgs e)
        {
            if (IsHidden)
            {
                ModelChanged(false);
                if (IsHidden)
                    Show();            
            }
            else
            {
                Hide();
            }
        }
        /*
        public override void Show()
        {
            //ToolManager.Instance.DockPanel.Size = new Size(Math.Max(Size.Width, 510), Size.Height);
            //if (Utility.DrawPanel != null)
            //    Utility.DrawPanel.Width = MainForm.ActiveForm.Width - 510;
            if (CurrentModel.Selected.Count == 1 && CurrentModel.Selected[0].Item is Core.Module)
            {
                if (CurrentModel.Selected[0].Item != TargetContainer)
                    TargetContainer = CurrentModel.Selected[0].Item as Core.Module;
                base.Show();
            }
            else
            {
                if (TargetContainer != CurrentModel.BackEndModel)
                    TargetContainer = CurrentModel.BackEndModel;
                base.Show();
            }
            //Utility.Panel.Focus();
        }
        */
        public ModuleViewer()
        {
            InitializeComponent();

            SetStyle(ControlStyles.AllPaintingInWmPaint |
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.ResizeRedraw |
                ControlStyles.UserPaint, true);
            
            Text = "Module Overview";
            _bHasContextMenuItems = true;
            _bHasMenuItems = false;
            _bRequiresNewToolWindow = false;
            ToolManager.Instance.RegisterTool(Text, this);
            if (!ToolManager.Instance.PropertyEditors.Contains(this))
                ToolManager.Instance.PropertyEditors.Add(this);

            CurrentModel.SelectionChanged += new Model.SelectionChangedDelegate(Model_SelectionChanged);
            CurrentModel.ModelChanged += new Model.ModelChangedDelegate(CurrentModel_ModelChanged);
            propertyGrid1.SelectedObject = CurrentModel;
            TargetContainer = CurrentModel.BackEndModel;
        }

        public override bool Handles(List<Type> oTypes)
        {
            bool bResult = true;
            foreach (Type t in oTypes)
            {
                bResult &= Handles(t);
                if (!bResult) return false;
            }
            return bResult;
        }

        private bool Handles(Type t)
        {
            return (Utility.IsType(typeof(Objects.ContainerGlyph), t));
        }

        public override void SetupContextMenu(ToolStripMenuItem oStrip)
        {
            oStrip.Text = "Module/Compartment editor...";
            oStrip.ToolTipText = "Provides a convenient way of changing properties of selected Container";
            oStrip.Click += new EventHandler(oItem_Click);
        }

        public override void oItem_Click(object sender, EventArgs e)
        {
            OnItemDoubleClick(null);
        }

        public override void OnItemDoubleClick(HandledMouseEventArgs e)
        {
            ModelChanged(true);
        }

        bool _Initializing = false;
        void ModelChanged(bool autoHide)
        {
            if (_Initializing) return;

            _Initializing = true;

            if (CurrentModel.Selected.Count != 1)
            {
                if (CurrentModel.Selected.Count == 0)
                {
                    TargetContainer = CurrentModel.BackEndModel;
                    if (IsHidden)
                        Show();
                }
                else
                {
                    TargetContainer = null;
                    //if (!IsHidden)
                    //    Hide();
                }
            }
            else
            {
                Core.Item item = CurrentModel.Selected[0].Item;

                if (item is Core.Container)
                {
                    TargetContainer = (Core.Container)item;
                    if (IsHidden && autoHide)
                        Show();
                }
                else
                {
                    TargetContainer = null;
                    if (!IsHidden && autoHide)
                        Hide();
                }
            }
            if (!IsHidden)
                if (CurrentModel.Selected.Count > 0)
                {
                    propertyGrid1.SelectedObjects = CurrentModel.Selected.ToArray();
                }
                else
                {
                    propertyGrid1.SelectedObject = CurrentModel;
                }
            _Initializing = false;
        }

        void CurrentModel_ModelChanged(object sender, EventArgs e)
        {
            ModelChanged(false);
        }

        void Model_SelectionChanged(object sender, Model.SelectionEventArgs e)
        {
            ModelChanged(false);
            
            foreach (Objects.IDrawable id in CurrentModel.Selected)
            {
                if (id.Item is Core.Species)
                {
                    reactionsDataView.CurrentCell = null;
                    partDataView.CurrentCell = null;
                    paramDataView.CurrentCell = null;
                    
                    if (!(_TargetContainer is Core.Module && _TargetContainer.Parent != null))
                    {
                        List<Species> species = speciesDataView.DataSource as List<Species>;
                        if (species != null)
                        {
                            int i = 0;
                            foreach (Species s in species)
                            {
                                if (s.Item() == id.Item as Core.Species && (speciesDataView.CurrentCell == null || speciesDataView.CurrentCell.RowIndex != i))
                                {
                                    speciesDataView.CurrentCell = speciesDataView.Rows[i].Cells[0];
                                    break;
                                }
                                ++i;
                            }
                        }
                    }
                    else
                    {
                        List<ModularSpecies> species = speciesDataView.DataSource as List<ModularSpecies>;
                        if (species != null)
                        {
                            int i = 0;
                            foreach (Species s in species)
                            {
                                if (s.Item() == id.Item as Core.Species && (speciesDataView.CurrentCell == null || speciesDataView.CurrentCell.RowIndex != i))
                                {
                                    speciesDataView.CurrentCell = speciesDataView.Rows[i].Cells[0];
                                    break;
                                }
                                ++i;
                            }
                        }
                    }
                }
                else
                    if (id.Item is Core.Edge)
                    {
                        speciesDataView.CurrentCell = null;                        
                        partDataView.CurrentCell = null;
                        paramDataView.CurrentCell = null;

                        List<Reaction> reactions = reactionsDataView.DataSource as List<Reaction>;
                        if (reactions != null)
                        {
                            int i = 0;
                            foreach (Reaction r in reactions)
                            {
                                if (r.Item() == id.Item as Core.Edge && (reactionsDataView.CurrentCell == null || reactionsDataView.CurrentCell.RowIndex != i))
                                {
                                    reactionsDataView.CurrentCell = reactionsDataView.Rows[i].Cells[0];
                                    break;
                                }
                                ++i;
                            }
                        }
                    }
                    else
                        if (id.Item is Core.Part)
                        {
                            speciesDataView.CurrentCell = null;
                            reactionsDataView.CurrentCell = null;                            
                            paramDataView.CurrentCell = null;

                            if (!(_TargetContainer is Core.Module && _TargetContainer.Parent != null))
                            {
                                List<Part> parts = partDataView.DataSource as List<Part>;
                                if (parts != null)
                                {
                                    int i = 0;
                                    foreach (Part p in parts)
                                    {
                                        if (p.Item() == id.Item as Core.Part && (partDataView.CurrentCell == null || partDataView.CurrentCell.RowIndex != i))
                                        {
                                            partDataView.CurrentCell = partDataView.Rows[i].Cells[0];
                                            break;
                                        }
                                        ++i;
                                    }
                                }
                            }
                            else
                            {
                                List<ModularPart> parts = partDataView.DataSource as List<ModularPart>;
                                if (parts != null)
                                {
                                    int i = 0;
                                    foreach (Part p in parts)
                                    {
                                        if (p.Item() == id.Item as Core.Part && (partDataView.CurrentCell == null || partDataView.CurrentCell.RowIndex != i))
                                        {
                                            partDataView.CurrentCell = partDataView.Rows[i].Cells[0];
                                            break;
                                        }
                                        ++i;
                                    }
                                }
                            }
                        }
            }
        }
        /// <summary>
        /// This class contains a name->Edge pair. It is used by ModuleViewer to manipulate an edge
        /// </summary>
        public class Reaction : IComparable<Reaction>
        {
            public int CompareTo(Reaction other)
            {
                return ID.CompareTo(other.ID);
            }

            private string _ID;
            private Core.Edge edge;
            private ModuleViewer viewer;
            private string _Rate;

            public virtual Core.Edge Item()
            {
                return edge;
            }

            public string ID
            {
                get
                {
                    return _ID;
                }
                set
                {
                    if (edge != null && value != edge.ID)
                    {
                        HistoryManager.History.SetControllPoint("ID changed :" + value);
                        edge.ID = value;
                        //viewer.UpdateLists();
                        CurrentModel.OnModelChanged(EventArgs.Empty);
                        Utility.Refresh();
                    }
                }
            }
            public string Rate
            {
                get
                {
                    return _Rate;
                }
                set
                {
                    if (edge != null && edge.Rate != value)
                    {
                        HistoryManager.History.SetControllPoint("Rate changed :" + edge.ID);
                        edge.Rate = value;
                        if (edge.PossibleErrorInRate)
                            Utility.SetMessage("WARNING: rate expression is not a function of the reactants.");
                        if (edge.Drawable is Objects.BezierConnector)
                        {
                            ((Objects.BezierConnector)edge.Drawable).GenerateModifiers();
                        }
                        //viewer.UpdateLists();
                        CurrentModel.OnModelChanged(EventArgs.Empty);
                    }
                }
            }
            public Reaction(string id, Core.Edge e, ModuleViewer mv) 
            {
                _ID = id;
                edge = e;
                Core.Module module = mv.TargetContainer as Core.Module;
                _Rate = e.GetRate(module);
                viewer = mv;
            }
            public Reaction(string id, Core.Edge e, Hashtable items, ModuleViewer mv)
            {
                //e.Update(); //expensive...
                _ID = id;
                edge = e;
                Core.Module module = mv.TargetContainer as Core.Module;
                _Rate = e.GetRate(module, items);
                viewer = mv;
            }
            public void Remove()
            {
                if (edge != null)
                {
                    HistoryManager.History.SetControllPoint("reaction removed :" + edge.ID);
                    if (edge.Drawable != null) edge.Drawable.Remove();
                    edge.Remove();
                    //viewer.UpdateLists();
                    CurrentModel.OnModelChanged(EventArgs.Empty);
                }
            }
        }
        /// <summary>
        /// This class contains a name->Species pair. It is used by ModuleViewer to manipulate an edge
        /// </summary>
        public class Species : IComparable<Species>
        {
            public int CompareTo(Species other)
            {
                return ID.CompareTo(other.ID);
            }
            protected string _ID;
            protected ModuleViewer viewer;
            protected Core.Species species;

            public virtual Core.Species Item()
            {
                return species;
            }

            public virtual string ID
            {
                get
                {
                    return _ID;
                }
                set
                {
                    if (species != null && value != species.ID)
                    {
                        HistoryManager.History.SetControllPoint("ID changed : " + value);
                        species.ID = value;
                        //viewer.UpdateLists();                        
                        Utility.Refresh();
                        CurrentModel.OnModelChanged(EventArgs.Empty);
                    }
                }
            }
            public virtual double Concentration
            {
                get
                {
                    if (species != null)
                        return species.Concentration;
                    else
                        return 0;
                }
                set
                {
                    if (species != null && species.Concentration != value)
                    {
                        HistoryManager.History.SetControllPoint("Concentration changed : " + species.ID);
                        species.Concentration = value;
                        if (species.Boundary) //changing boundary is similar to changing parameter
                            CurrentModel.OnModelChanged(EventArgs.Empty);
                    }
                }
            }
            public virtual bool Constant
            {
                get
                {
                    if (species != null)
                        return species.GetBoundary(viewer.TargetContainer as Core.Module);
                    else
                        return false;
                }
                set
                {
                    if (species != null && value != species.Boundary)
                    {
                        HistoryManager.History.SetControllPoint("Boundary condition changed : " + species.ID);
                        species.Boundary = value;
                        Utility.Refresh();
                        CurrentModel.OnModelChanged(EventArgs.Empty);
                    }
                }
            }
            public Species(string id, Core.Species s, ModuleViewer mv) 
            { 
                species = s;
                _ID = id;
                viewer = mv; 
            }
            public void Remove()
            {
                if (species != null)
                {
                    HistoryManager.History.SetControllPoint("Specied removed : " + species.ID);
                    if (species.Drawable != null) species.Drawable.Remove();
                    species.Remove();
                    //viewer.UpdateLists();
                    CurrentModel.OnModelChanged(EventArgs.Empty);
                }
            }
        }

        /// <summary>
        /// This is a species data item with another field called InputOutput
        /// which indicates whether this species is used as an I/O item in the module
        /// </summary>
        public class ModularSpecies : Species
        {
            public override string ID
            {
                get
                {
                    return base.ID;
                }
                set
                {
                    base.ID = value;
                }
            }
            public override double Concentration
            {
                get
                {
                    return base.Concentration;
                }
                set
                {
                    base.Concentration = value;
                }
            }
            public override bool Constant
            {
                get
                {
                    return base.Constant;
                }
                set
                {
                    base.Constant = value;
                }
            }
            public bool Exposed
            {
                get
                {
                    if (species != null)
                    {
                        if (species.ParentModule != null)
                            return species.ParentModule.GetMappingTo(species) != null || species.ParentModule.GetMappingFrom(species) != null;
                    }
                    return false;
                }
                set
                {
                    if (species != null)
                    {
                        Core.Module parent = species.ParentModule;
                        if (parent != null)
                        {
                            if (value)
                            {
                                if (parent.GetMappingTo(species) == null)
                                    parent.SetMapping(species, species);  //trick!
                            }
                            else
                            {
                                parent.SetMapping(species, null); //remove
                            }
                            if (parent.Drawable is Objects.ModuleGlyph)
                            {
                                bool encapsulation = ((Objects.ModuleGlyph)parent.Drawable).Encapsulate;
                                ((Objects.ModuleGlyph)parent.Drawable).Encapsulate = !encapsulation;
                                ((Objects.ModuleGlyph)parent.Drawable).Encapsulate = encapsulation;
                            }
                        }
                    }
                }
            }
            public ModularSpecies(string id, Core.Species s, ModuleViewer mv) : 
                base(id,s,mv)
            { 
            }
        }

        /// <summary>
        /// This class contains a name->Part pair. It is used by ModuleViewer to manipulate an edge
        /// </summary>
        public class Part : IComparable<Part>
        {
            public int CompareTo(Part other)
            {
                return ID.CompareTo(other.ID);
            }

            protected ModuleViewer viewer;
            protected Core.Part part;
            protected string _ID;
            protected string _Rate;

            public virtual Core.Part Item()
            { 
                return part;
            }

            public virtual string ID
            {
                get
                {
                    return _ID;
                }
                set
                {
                    if (part != null && value != part.ID)
                    {
                        HistoryManager.History.SetControllPoint("ID changed :" + value);
                        part.ID = value;
                        //viewer.UpdateLists();
                        Utility.Refresh();
                        CurrentModel.OnModelChanged(EventArgs.Empty);                        
                    }
                }
            }
            public virtual string PoPS
            {
                get
                {
                    return _Rate;
                }
                set
                {
                    if (part != null && part.PoPS.Rate != value)
                    {
                        HistoryManager.History.SetControllPoint("PoPS changed :" + part.ID);
                        part.PoPS.Rate = value;
                        if (part.Drawable is Objects.PartGlyph)
                        {
                            ((Objects.PartGlyph)part.Drawable).GenerateModifiers();
                        }
                        //viewer.UpdateLists();
                        Utility.Refresh();
                        CurrentModel.OnModelChanged(EventArgs.Empty);
                    }
                }
            }
            public Part(string id, Core.Part p, ModuleViewer mv)
            {
                //p.PoPS.Update();
                _ID = id;
                part = p;
                Core.Module module = mv.TargetContainer as Core.Module;
                _Rate = p.PoPS.GetRate(module);
                viewer = mv; 
            }
            public Part(string id, Core.Part p, Hashtable allItems, ModuleViewer mv)
            {
                //p.PoPS.Update();
                _ID = id;
                part = p;
                Core.Module module = mv.TargetContainer as Core.Module;
                _Rate = p.PoPS.GetRate(module,allItems);
                viewer = mv;
            }
            public void Remove()
            {
                if (part != null)
                {
                    if (part.Drawable != null) part.Drawable.Remove();
                    part.Remove();
                    CurrentModel.OnModelChanged(EventArgs.Empty);
                }
            }
        }

        /// <summary>
        /// This is a species data item with another field called InputOutput
        /// which indicates whether this species is used as an I/O item in the module
        /// </summary>
        public class ModularPart : Part
        {
            public override string ID
            {
                get
                {
                    return base.ID;
                }
                set
                {
                    base.ID = value;
                }
            }
            public override string PoPS
            {
                get
                {
                    return base.PoPS;
                }
                set
                {
                    base.PoPS = value;
                }
            }
            public bool Exposed
            {
                get
                {
                    if (part != null)
                    {
                        if (part.ParentModule != null)
                            return part.ParentModule.GetMappingTo(part) != null || part.ParentModule.GetMappingFrom(part) != null;
                    }
                    return false;
                }
                set
                {
                    if (part != null)
                    {
                        Core.Module parent = part.ParentModule;
                        if (parent != null)
                        {
                            if (value)
                            {
                                if (parent.GetMappingTo(part) == null)
                                    parent.SetMapping(part, part);  //trick!
                            }
                            else
                            {
                                parent.SetMapping(part, null); //remove
                            }
                        }
                    }
                }
            }
            public ModularPart(string id, Core.Part p, ModuleViewer mv):
                base(id, p, mv)
            {
            }
            public ModularPart(string id, Core.Part p, Hashtable allItems, ModuleViewer mv) :
                base(id, p, allItems, mv)
            {
            }
        }

        /// <summary>
        /// This class contains a name->Parameter pair. It is used by ModuleViewer to manipulate an edge
        /// </summary>
        public class Parameter : IComparable<Parameter>
        {
            public int CompareTo(Parameter other)
            {
                return ID.CompareTo(other.ID);
            }

            public ModuleViewer viewer;
            private string _ID;
            private Core.Parameter _Parameter;

            public string ID
            {
                get
                {
                    return _ID;
                }
                set
                {
                    if (viewer == null || _ID == value) return;

                    Core.Module module = viewer.TargetContainer as Core.Module;
                    if (module != null)
                    {
                        module.ChangeParameterName(_ID, value);
                        //viewer.UpdateLists();
                        CurrentModel.OnModelChanged(EventArgs.Empty);
                    }
                }
            }
            public double Value
            {
                get
                {
                    if (_Parameter != null)
                        return _Parameter.Value;
                    else
                        return double.NaN;
                }
                set
                {
                    if (_Parameter.Value != value)
                    {
                        HistoryManager.History.SetControllPoint("Parameter changed : " + _ID);
                        _Parameter.Value = value;
                        CurrentModel.OnModelChanged(EventArgs.Empty);
                    }
                }
            }

            public Parameter(string n, Core.Parameter parameter, ModuleViewer moduleviewer)
            {
                _ID = n;
                _Parameter = parameter;
                viewer = moduleviewer;
            }
        }

        /// <summary>
        /// This class contains a name->rule pair. It is used by ModuleViewer to manipulate rules
        /// </summary>
        public class Rule : IComparable<Rule>
        {
            public int CompareTo(Rule other)
            {
                return ID.CompareTo(other.ID);
            }

            public ModuleViewer viewer;
            private string _ID;

            public string ID
            {
                get
                {
                    return _ID;
                }
                set
                {
                    if (viewer == null || _ID == value) return;

                    Core.Module module = viewer.TargetContainer as Core.Module;
                    if (module != null)
                    {
                        module.ChangeRuleName(_ID, value);
                        CurrentModel.OnModelChanged(EventArgs.Empty);
                    }
                }
            }
            public string Formula
            {
                get
                {
                    if (viewer != null)
                    {
                        Core.Module module = viewer.TargetContainer as Core.Module;
                        if (module != null && module.LocalRules.ContainsKey(_ID))
                        {
                            object o = module.LocalRules[_ID];
                            if (o is string)
                                return (string)o;
                        }
                    }
                    return "";
                }
                set
                {
                    if (viewer == null) return;

                    Core.Module module = viewer.TargetContainer as Core.Module;
                    if (module != null && module.LocalRules.ContainsKey(_ID))
                    {
                        HistoryManager.History.SetControllPoint("Rule changed :" + _ID);
                        module.SetRule(_ID,value);
                        CurrentModel.OnModelChanged(EventArgs.Empty);
                    }
                }
            }

            public Rule(string n, ModuleViewer moduleviewer)
            {
                _ID = n;
                viewer = moduleviewer;
            }
        }

        private Core.Container _TargetContainer = null;
        public Core.Container TargetContainer
        {
            get { return _TargetContainer; }
            set
            {
                if (value != null)
                {
                    _TargetContainer = value;
                    textBox1.Text = _TargetContainer.ID;
                    if (_TargetContainer is Core.Module)
                    {
                        label1.Text = "Module ID :  ";
                        this.Text = "Module Viewer";
                        checkEncapsulate.Visible = true;
                        Objects.ModuleGlyph glyph = _TargetContainer.Drawable as Objects.ModuleGlyph;
                        if (glyph != null)
                        {
                            checkEncapsulate.Checked = glyph.Encapsulate;
                            checkSchematic.Checked = (glyph.View == Athena.Objects.IDrawable.ViewType.Schematic);
                        }
                    }
                    else
                    {
                        label1.Text = "Container ID:";
                        this.Text = "Container Viewer";
                        checkEncapsulate.Visible = false;
                        Objects.IDrawable glyph = _TargetContainer.Drawable;
                        if (glyph != null)
                        {
                            checkSchematic.Checked = (glyph.View == Athena.Objects.IDrawable.ViewType.Schematic);
                        }
                    }
                    UpdateLists();                    
                }
            }
        }

        public void UpdateLists()
        {
            _Initializing = true;
            try
            {
                if (_TargetContainer != null)
                {
                    List<Reaction> _Reactions = new List<Reaction>();
                    List<Species> _Species = new List<Species>();
                    List<Parameter> _Parameters = new List<Parameter>();
                    List<Part> _Parts = new List<Part>();
                    List<Rule> _Rules = new List<Rule>();

                    /*
                    reactionsDataView.DataSource = null;
                    speciesDataView.DataSource = null;
                    paramDataView.DataSource = null;
                    partDataView.DataSource = null;
                    */

                    Hashtable items = _TargetContainer.AllItems;

                    foreach (string id in items.Keys)
                    {
                        Core.Item item = items[id] as Core.Item;
                        if (item != null)
                        {
                            if (item is Core.Edge && ((Core.Edge)item).IsReaction)
                                _Reactions.Add(new Reaction(id, item as Core.Edge, items, this));
                            else
                            if (item is Core.Species)
                                if (_TargetContainer is Core.Module && _TargetContainer.Parent != null)
                                    _Species.Add(new ModularSpecies(id, item as Core.Species, this));
                                else
                                    _Species.Add(new Species(id, item as Core.Species, this));
                            else
                            if (item is Core.Part)
                                if (_TargetContainer is Core.Module && _TargetContainer.Parent != null)
                                    _Parts.Add(new ModularPart(id, item as Core.Part, items, this));
                                else
                                    _Parts.Add(new Part(id, item as Core.Part, items, this));
                        }
                    }
                    if (_TargetContainer is Core.Module)
                    {
                        //((Core.Module)_TargetContainer).UpdateParameters();
                        Hashtable parameters = ((Core.Module)_TargetContainer).GlobalParameters;
                        foreach (string s in parameters.Keys)
                        {
                            if (parameters[s] is Core.Parameter)
                                _Parameters.Add(new Parameter(s, parameters[s] as Core.Parameter, this));
                        }
                        Hashtable rules = ((Core.Module)_TargetContainer).GlobalRules;
                        foreach (string s in rules.Keys)
                        {
                            _Rules.Add(new Rule(s, this));
                        }

                        _Parameters.Sort();
                        _Rules.Sort();

                        paramDataView.DataSource = _Parameters;
                        rulesDataView.DataSource = _Rules;
                    }
                    else
                    {
                        paramDataView.DataSource = null;
                        rulesDataView.DataSource = null;
                    }

                    _Reactions.Sort();
                    _Species.Sort();
                    _Parts.Sort();

                    reactionsDataView.DataSource = _Reactions;

                    if (_TargetContainer is Core.Module && _TargetContainer.Parent != null)
                    {
                        List<ModularSpecies> species2 = new List<ModularSpecies>();
                        List<ModularPart> parts2 = new List<ModularPart>();

                        foreach (Species s in _Species) species2.Add(s as ModularSpecies);
                        foreach (Part p in _Parts) parts2.Add(p as ModularPart);

                        speciesDataView.DataSource = species2;
                        partDataView.DataSource = parts2;
                    }
                    else
                    {
                        speciesDataView.DataSource = _Species;
                        partDataView.DataSource = _Parts;
                    }

                    if (_TargetContainer is Core.Module)
                    {
                        List<string> crosstalks = ((Core.Module)_TargetContainer).CrossTalk(items);
                        if (crosstalks.Count > 0)
                        {
                            Utility.SetMessage("CROSSTALK between: " + string.Join(",",crosstalks.ToArray()));
                        }
                    }
                }

                speciesDataView.CurrentCell = null;
                reactionsDataView.CurrentCell = null;
                partDataView.CurrentCell = null;
                paramDataView.CurrentCell = null;
            }
            catch (Exception) { }
            _Initializing = false;
        }
        
        void reactionsDataView_RowsRemoved(object sender, System.Windows.Forms.DataGridViewRowsRemovedEventArgs e)
        {
            if (reactionsDataView.DataSource is List<Reaction>)
            {
                List<Reaction> list = reactionsDataView.DataSource as List<Reaction>;
                if (list != null && list.Count > e.RowIndex)
                    list[e.RowIndex].Remove();
            }
        }

        void speciesDataView_RowsRemoved(object sender, System.Windows.Forms.DataGridViewRowsRemovedEventArgs e)
        {
            if (speciesDataView.DataSource is List<Species>)
            {
                List<Species> list = speciesDataView.DataSource as List<Species>;
                if (list != null && list.Count > e.RowIndex)
                    list[e.RowIndex].Remove();
            }
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            if (_TargetContainer != null)
            {
                StringBuilder name = new StringBuilder();
                foreach (char c in textBox1.Text.ToCharArray())
                {
                    if ((char.IsDigit(c) && name.Length > 0) || char.IsLetter(c) || c == '_')
                        name.Append(c);
                }
                _TargetContainer.ID = name.ToString();
                CurrentModel.OnModelChanged(EventArgs.Empty);
                Utility.Refresh();
            }

            //Utility.Panel.Focus();
        }

        

        private void reactionsDataView_DataError(object sender, DataGridViewDataErrorEventArgs e)
        {
            Utility.SetMessage("Incorrect value");
            e.Cancel = true;
        }

        void setView(Athena.Objects.IDrawable.ViewType view)
        {
            if (CurrentModel.Selected.Count > 0)
            {
                foreach (Objects.IDrawable id in CurrentModel.Selected)
                {
                    id.View = view;
                }
            }
            else
            {
                foreach (Objects.IDrawable id in CurrentModel.Drawables)
                {
                    id.View = view;
                }
            }
        }

        private void checkSchematic_CheckedChanged(object sender, EventArgs e)
        {
            HistoryManager.History.SetControllPoint("View changed");

            if (checkSchematic.Checked)
                setView(Athena.Objects.IDrawable.ViewType.Schematic);
            else
                setView(Athena.Objects.IDrawable.ViewType.Block);
            Utility.Refresh();
        }

        private void checkEncapsulate_CheckedChanged(object sender, EventArgs e)
        {
            if (CurrentModel.Selected.Count > 0)
            {
                HistoryManager.History.SetControllPoint("Module encapsulated");
                foreach (Objects.IDrawable id in CurrentModel.Selected)
                {
                    if (id is Objects.ModuleGlyph)
                        ((Objects.ModuleGlyph)id).Encapsulate = checkEncapsulate.Checked;
                }
                CurrentModel.OnModelChanged(EventArgs.Empty);
                Utility.Refresh();
            }
        }

        private void ModuleViewer_Leave(object sender, EventArgs e)
        {   
            Utility.Panel.Focus();
        }

        /// <summary>
        /// Prevent some nasty keys ...
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="keyData"></param>
        /// <returns></returns>
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (!Focused) return false;

            switch (keyData)
            {
                case Keys.Up:
                case Keys.Down:
                case Keys.Back:
                case Keys.Tab:
                case Keys.Enter:
                case Keys.Home:
                case Keys.Home & Keys.Shift:
                    return true;

                default:
                    return base.ProcessCmdKey(ref msg, keyData);
            }
        }

        private void propertyGrid1_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
        {
            HistoryManager.History.SetControllPoint("property changed");
            CurrentModel.OnModelChanged(EventArgs.Empty);
            Utility.Refresh();
        }
        private void newruleButton_Click(object sender, EventArgs e)
        {
            try
            {
                HistoryManager.History.SetControllPoint("New Rule added");

                Core.Module module = _TargetContainer as Core.Module;

                if (module == null) return;

                string name = module.RequestNewParameterName("q");

                module.SetRule(name, "time;");

                CurrentModel.OnModelChanged(EventArgs.Empty);
            }
            catch (Exception)
            {
                Utility.SetMessage("Error adding rule");
            }
        }

        private void speciesDataView_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            try
            {
                object o = speciesDataView.CurrentCell.Value;
                int row = speciesDataView.CurrentCell.RowIndex;
                int col = speciesDataView.CurrentCell.ColumnIndex;

                if (_TargetContainer is Core.Module && _TargetContainer.Parent != null)
                {
                    List<ModularSpecies> s = speciesDataView.DataSource as List<ModularSpecies>;
                    if (s != null && row < s.Count && s[row] != null && s[row].Item() != null && s[row].Item().Drawable != null)
                    {
                        CurrentModel.DeselectItems(false);
                        CurrentModel.SelectItem(s[row].Item().Drawable, true);
                    }
                }
                else
                {
                    List<Species> s = speciesDataView.DataSource as List<Species>;
                    if (s != null && row < s.Count && s[row] != null && s[row].Item() != null && s[row].Item().Drawable != null)
                    {
                        CurrentModel.DeselectItems(false);
                        CurrentModel.SelectItem(s[row].Item().Drawable, true);
                    }
                }

                if (o is bool)
                {
                    if (_TargetContainer is Core.Module && _TargetContainer.Parent != null)
                    {
                        List<ModularSpecies> species = speciesDataView.DataSource as List<ModularSpecies>;
                        if (species != null && species.Count > row)
                        {
                            if (col == 2)
                                species[row].Constant = !((bool)o);
                            else
                                species[row].Exposed = !((bool)o);
                        }
                    }
                    else
                    {
                        List<Species> species = speciesDataView.DataSource as List<Species>;
                        if (species != null && species.Count > row && col == 2)
                        {
                            species[row].Constant = !((bool)o);
                        }
                    }
                }
                Utility.Refresh();
            }
            catch (Exception)
            {
                Utility.SetMessage("Error changing value");
            }
        }

        private void reactionsDataView_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            try
            {
                int row = reactionsDataView.CurrentCell.RowIndex;

                List<Reaction> s = reactionsDataView.DataSource as List<Reaction>;
                if (s != null && (row < s.Count) && s[row] != null && s[row].Item() != null && s[row].Item().Drawable != null)
                {
                    CurrentModel.DeselectItems(false);
                    CurrentModel.SelectItem(s[row].Item().Drawable, true);
                }

                Utility.Refresh();
            }
            catch (Exception)
            {
                Utility.SetMessage("Error changing value");
            }
        }

        private void partDataView_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            try
            {
                int row = partDataView.CurrentCell.RowIndex;

                if (_TargetContainer is Core.Module && _TargetContainer.Parent != null)
                {
                    List<ModularPart> s = partDataView.DataSource as List<ModularPart>;
                    if (s != null && row < s.Count && s[row] != null && s[row].Item() != null && s[row].Item().Drawable != null)
                    {
                        CurrentModel.DeselectItems(false);
                        CurrentModel.SelectItem(s[row].Item().Drawable,true);
                    }
                }
                else
                {
                    List<Part> s = partDataView.DataSource as List<Part>;
                    if (s != null && row < s.Count && s[row] != null && s[row].Item() != null && s[row].Item().Drawable != null)
                    {
                        CurrentModel.DeselectItems(false);
                        CurrentModel.SelectItem(s[row].Item().Drawable,true);
                    }
                }
                Utility.Refresh();
            }
            catch (Exception)
            {
                Utility.SetMessage("Error changing value");
            }
        }
    }
}
